package com.company.dcm.controller;

import com.company.dcm.common.R;
import com.company.dcm.entity.Ota;
import com.company.dcm.server.protocol.enums.ProtocolMessageTypeEnum;
import com.company.dcm.server.protocol.enums.ProtocolTaskOptionEnum;
import com.company.dcm.server.tcp.ConnectionManager;
import com.company.dcm.server.tcp.MessageSender;
import com.company.dcm.service.Device_otaService;
import com.company.dcm.service.Impl.TaskService;
import com.company.dcm.service.OTAService;
import com.company.dcm.utils.BinHexUtil;
import com.company.dcm.utils.FileUtils;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

@Slf4j
@RestController
@RequestMapping("/OTA")
public class OTAController {
    @Autowired
    private TaskService taskService;

    @Autowired
    OTAService otaService;

    @Autowired
    Device_otaService deviceOtaService;

    private static final String OTAFilePath = "/usr/share/nginx/html/detection/";

//    private static final String OTAFilePath = "D:/company_project/";




    @PostMapping("/upload")
    public R upload(@RequestParam("file") MultipartFile OTAFile,@RequestParam("hardwareVersion") String hardwareVersion,@RequestParam("softwareVersion") String softwareVersion,@RequestParam("productType") String productType) throws IOException, InterruptedException {
        String safePath = FileUtils.saveToTemp(OTAFile);

        String taskId = taskService.createTask();

        if (!otaService.duplicate(OTAFile,OTAFilePath,hardwareVersion,softwareVersion,productType)){
            return R.error("该固件包已存在");
        }
        taskService.updateProgress(taskId, 0.3F);

        otaService.upload(OTAFile,OTAFilePath,hardwareVersion,softwareVersion,productType,taskId);

        return R.success(taskId);
    }

    // 根据任务ID查询进度
    @GetMapping("/get/{taskId}")
    public R getProgress(@PathVariable String taskId) {
        return R.success(taskService.getProgress(taskId));
    }

    @GetMapping("/getOTAList")
    public R getOTAList(@RequestParam String product_type){

        List<Ota> OTAList = otaService.getOTAList(product_type);


        return R.success(OTAList);

    }

    @PostMapping("/deleteOta")
    public R deleteOta(@RequestParam String OtaId){

        if (otaService.deleteOta(OtaId)){
            return R.success("删除成功");
        } else {
            return R.error("删除失败");
        }

    }

    @PostMapping("/editOta")
    public R updateOta(@RequestParam("otaId") Integer otaId,@RequestParam(value = "OTAFile",required = false) MultipartFile OTAFile,@RequestParam("hardwareVersion") String hardwareVersion,@RequestParam("softwareVersion") String softwareVersion,@RequestParam("productType") String productType) throws IOException {

        if (otaService.updateOta(otaId,OTAFile,OTAFilePath,hardwareVersion,softwareVersion,productType)){
            return R.success("更新成功");
        } else {
            return R.error("更新失败");
        }

    }

    @PostMapping("/updateAllOTA")//是否全部更新
    public R updateAllOTA(@RequestParam String SoftwareVersion,@RequestParam String HardwareVersion ) throws IOException {

        if (SoftwareVersion.isEmpty() || HardwareVersion.isEmpty()){
            return R.error("软硬件版本不可为空");
        }

        Set<String> devices = ConnectionManager.getAllSerials();

        byte[] bytes = MessageSender.handleMessage(ProtocolMessageTypeEnum.INFORMATION,
                ProtocolTaskOptionEnum.NOTICE_OTA_UPDATED,SoftwareVersion,HardwareVersion);

        log.info("bytes" + Arrays.toString(bytes));
        log.info(devices.toString());

        for ( String device : devices ){
            log.info("device" + ConnectionManager.serialToIpPort.get(device));
            MessageSender.sendMessageByIP(ConnectionManager.serialToIpPort.get(device).split(":")[0], bytes);
            deviceOtaService.updateOTA(ConnectionManager.serialToIpPort.get(device).split(":")[0]);
        }

        return R.success("正在更新中");

    }

    @PostMapping("/updateOTA")//更新部分
    public R updateOTA(@RequestBody List<String> devices,@RequestParam String softwareVersion,@RequestParam String hardwareVersion) throws IOException {

        if (softwareVersion.isEmpty() || hardwareVersion.isEmpty()){
            return R.error("软硬件版本不可为空");
        }

        System.out.println(devices);

        byte[] bytes = MessageSender.handleMessage(ProtocolMessageTypeEnum.INFORMATION,
                ProtocolTaskOptionEnum.NOTICE_OTA_UPDATED,softwareVersion,hardwareVersion);

        log.info("bytes" + Arrays.toString(bytes));

        for ( String device : devices ){
            log.info("device" + ConnectionManager.serialToIpPort.get(device));
            MessageSender.sendMessageByIP(ConnectionManager.serialToIpPort.get(device).split(":")[0], bytes);
            deviceOtaService.updateOTA(ConnectionManager.serialToIpPort.get(device).split(":")[0]);
        }

        return R.success("正在更新中");

    }

    @GetMapping("/getProductType")
    public R getProductType(){

        List<Object> types = otaService.getProductType();

        return R.success(types);

    }

    private final List<SseEmitter> emitters = new CopyOnWriteArrayList<>();

    // 客户端注册
    @GetMapping("/subscribe")
    public SseEmitter subscribe() {
        SseEmitter emitter = new SseEmitter(360_000L); // 超时时间
        emitters.add(emitter);
        emitter.onCompletion(() -> emitters.remove(emitter));
        return emitter;
    }

    // 主动推送方法
    public void sendEvent(byte[] data, ChannelHandlerContext ctx) {
        String deviceCode = BinHexUtil.byteArrayToAsciiString(data, 0, 8);
        deviceOtaService.saveDeviceByOtaUpdate(deviceCode,ctx);
        String msg = "";
        if (data[8] == 1){
            msg = "更新成功！";
        }else {
            msg = "更新失败！";
        }
        String finalMsg = msg;
        emitters.forEach(emitter -> {
            try {
                emitter.send(SseEmitter.event().data(finalMsg));
            } catch (IOException e) {
                // 处理异常
            }
        });
    }


    
}
